 LST OFF,NOASYM,NOVSYM,NOGEN
 X65816
 XREFSLOT 6
 SEG $00
*
************************************************************
*                                                          *
*            PRODOS 8 KERNEL 59.5K RAMDISK (REV-E)         *
*                                                          *
*            COPYRIGHT APPLE COMPUTER, INC., 1983-86       *
*                                                          *
*                     ALL RIGHTS RESERVED                  *
*                                                          *
************************************************************
*
**** Note that the "os" variable must be updated depending on
**** the system you are building.
*
ProDOS equ 0
EdNet equ 1
os equ ProDOS
*
* Creates 3 object files 
 SBTL 'EXTENDED 80 COL RAMDISK'
 DSECT
 ORG $42 
CMD DS 1,0 ;command from ProDOS
UNIT DS 1,0 ;unitnum from ProDOS
BUFPTR DS 2,0 ;User Buffer pointer
BLOCK DS 2,0 ;block requested
 DEND
*
XDIOERR EQU $27
XDWPERR EQU $2B ;write protect error
A1L EQU $3C
A1H EQU $3D ;SOURCE OF TRANSFER
A2L EQU $3E
A2H EQU $3F ;END OF SOURCE
A3L EQU $40
A3H EQU $41
A4L EQU $42
A4H EQU $43 ;DESTINATION OF TRANSFER
*
MOVE EQU $C311 ;monitor move data routine
XFER EQU $C314 ;monitor XFER control
*
EnblRAM2 EQU $C083 ;enable 2nd bank of LC
EnblRAM1 EQU $C08B ;enable 1st bank of LC
*
Store80Off EQU $C000
Store80On EQU $C001
Store80Sw EQU $C018
WRMAINRAM EQU $C004 ;Write data to main ram
WRCARDRAM EQU $C005 ;Write data to card ram
ALTZP EQU $C009 ;enable alternate ZP,STK,LC
REGZP EQU $C008 ;enable regular ZP,STK,LC
*
ABUF1 EQU $C00 ;temporary buffer
VBLOCK1 EQU $E00 ;where the Vdir goes
*
EnterCard EQU $200 ;card entry point
PassIt EQU $3ED ;XFER param 
*
 PAGE
 ORG EnterCard 
*
* After the main routine has determined that the command
* is ok, and the block to be read/written is within
* range, it tranfers control to this routine.  This routine
* remaps the block requested as follows:
*     Request blocks 0,1 :invalid
*                      2 :returns VDIR (card block 3)
*                      3 :returns bitmap (synthesized)
*                      4 :returns card block 0
*                 $5-$5F :returns card blocks $5-$5F
*                $60-$67 :returns blocks $68-$7F in bank 1 of
*                           card's language card
*                $68-$7F :returns blocks $68-$7F in bank 2
*                           of card's language card
*
DoCmd LDA Store80Sw ;Read 80STORE
 PHA ;save for later
 STA Store80Off ;turn off 80STORE
*
 LDX #4 ;move the params for our use  
DoCmd1 LDA CMD,X ;CMD,UNIT,BUFPTR,&BLOCK(lo)
 STA TCMD,X ;->TCMD,TUNIT,R2L,R2,R1 
 DEX
 BPL DoCMD1
 AND FormatFlag ;Format the volume first time 
 BNE DoCommand ;thru, or when requested 
*
DoFormat LDX BLOCK ;save R1 during format
 LDA #<VBLOCK1 ;block to be cleared
 JSR CLRBUF1 ;ClrBuf clears all buffers
 LDY #$3 ;Format volume in 2 chunks 
DF2 LDA Vdir,Y
 STA VBLOCK1+4,Y
 DEY
 BPL DF2
*
 lda #$FE ;Set last block as unusable to protect vectors
 sta bitmap+$F
 TYA ;Set bitmap bits to $FF
 LDY #$E ;15 bytes to set
DF2.1 STA BITMAP,Y 
 DEY
 BNE DF2.1
 STY BITMAP ;first byte=0
*
 LDY #$7 ;do other chunk
DF3 LDA Access,Y
 STA VBLOCK1+34,Y
 DEY
 BPL DF3 
 LDA FormatFlag ;if 0, set to FF 
 BNE DFX ;else exitcard
 STY FormatFlag ;Y=FF, won't format next time 
 STX R1 ;restore R1
*
* Now use the requested block number to determine
* which routine performs the transfer
*
DoCommand ASL R1 ;block requested->page requested
 LDA R1 ;get page requested
 CMP #$BF ;in Language card?
 BCS TLC1 ;yes, do it
CB1 CMP #6 ;bit map?
 BNE CB2 
 JMP TBMAP ;yes, transfer bitmap
CB2 JMP TREG ;else normal transfer
*
* When a block between $60 and $7F is requested, it must
* be spirited into/from the language card area of the 
* 64K card.  This requires a two-stage move: into the temp
* buffer and then to its real destination.
*
TLC1 TAX ;save R1 for later
 JSR SETPTR ;get direction
 PHP ;save direction
 BCS LCWrt ;it is a write
LCRd TXA ;get R1 back
 CMP #$CF ;which bank is it in
 BCS TLC2 ;in main bank
*
 ORA #$10 ;in secondary bank
 BNE TLC3 ;branch always
*
TLC2 STA EnblRAM2 ;turn on main $D000
 STA EnblRAM2
*
TLC3 STA R1 ;restore R1
 LDA R2 ;save R2 for later
 PHA
 LDX R2L 
 STA ALTZP ;now switch to other ZP
 LDA #<Abuf1 ;set R2 to Abuf 
 STA R2 
 LDA #>Abuf1  
 STA R2L
 JSR SetPtr ;set pointers
 TAY ;A=0 from SETPTR
TLC4 LDA (A1L),Y ;move A1,A2 to A4,A3
 STA (A4L),Y
 LDA (A2L),Y
 STA (A3L),Y
 DEY
 BNE TLC4
*
 STA REGZP ;restore normal ZP    
 STX R2L 
 PLA ;restore R2
 STA R2
 PLP ;get direction
DFX BCS XLCWrt ;write, done with move
*
 STA EnblRAM1 ;now switch MLI part of LC in
 STA EnblRAM1
 JSR BLOCKDO0 ;read, transfer Abuf to main
XLCWrt JMP ExitCard
*
LCWrt JSR BLOCKDO0 ;transfer main to Abuf
 JMP LCRd ;transfer Abuf to Lang card
*
* BLOCKDO transfers a block between main memory and the 
*  64K card.  R1 contains the page address of the block
*  in the card; R2 contains the page address of the block
*  in main memory.  The address in main memory is always
*  in the language card, so the language card is always
*  switched in.  If CMD is 2, a write is done (R2->R1);
*  if CMD is 1, a read is done (R1->R2).
*
BLOCKDO0 LDA #<ABUF1 ;set up R1 = Abuf 
BLOCKDO1 STA R1
BLOCKDO JSR SETPTR ;set pointers
 BCS BlockWrite ;it's a write
 STA WrMainRAM ;transfer buffer directly to main ram
 TAY ;0 left from SETPTR
BD1 LDA (A1L),Y ;transfer A1,A2 to A4,A3
 STA (A4L),Y
 LDA (A2L),Y
 STA (A3L),Y
 DEY
 BNE BD1
 STA WrCardRAM ;back the way it was
DoneWrt RTS ;MainWrt returns here 
*
BlockWrite LDA #>MainWrt ;pointers set up,
 STA PassIt ;pass control to main ram
 LDA #<MainWrt
 JMP Ex1 ;set PassIt+1 and transfer
*
* SETPTR is used by other routines to set up pointers
* and to detect read or write.
*
SETPTR LDA TCMD ;the rest depends on read 
 LSR A ;or write.  Which is it?
 BCS CMDWRT ;it's write
*
CMDRD LDA R2 ;get dest page
 STA A4H ;1st dest page (MOVE)
 STA A3H ;2nd dest page
 LDA R2L ;low byte dest page
 STA A4L ;1st dest page low
 STA A3L ;2nd dest page low
 LDA R1 ;get source page
 STA A1H ;1st source page
 STA A2H ;2nd source page
 LDA #0 ;source page aligned
 STA A1L ;1st source page
 STA A2L ;2nd source page
 BEQ CMDBOTH ;update second pages
*
CMDWRT LDA R2 ;get source page
 STA A1H ;1st source page
 STA A2H ;2nd source page
 LDA R2L ;get source page low
 STA A1L ;1st source page low
 STA A2L ;2nd source page low
 LDA R1 ;get dest page
 STA A4H ;1st dest page
 STA A3H ;2nd dest page
 LDA #0 ;dest page aligned
 STA A4L ;1st dest page
 STA A3L ;2nd dest page
*
CMDBOTH INC A2H ;update 2nd source page 
 INC A3H ;update 2nd dest page
 RTS
*
* TZIP is called if Blocks 0,1,4,5 are requested.
* On write it does nothing, on read, it returns 0's
*
TZIP JSR CLRBUF0 ;fill ABUF with 0's
 JSR BLOCKDO ;transfer them 0's
ZIPOUT JMP ExitCard ;and return
*
* CLRBUF fills the buffer indicated by R1 to 0's
* Should only be called on a read or format. 
*
CLRBUF0 LDA #<ABUF1 ;ABUF is temp buffer
CLRBUF1 STA R1 ;assign to BLOCK
CLRBUF2 JSR SETPTR ;set pointers
 TAY ;A set to 0 by setptr 
CLRBUF3 STA (A1L),Y
 STA (A2L),Y
 DEY
 BNE CLRBUF3 
 RTS
*
* TREG maps the requested block into the aux card
* so that 8K data files will be contiguous (the index
* blocks will not be placed within data).
*
TREG CMP #4 ;page 4 = vdir  
 BNE T1 ;not vdir, continue
 LDA #$7 ;else xfer block 7 
 BNE GoTimes2
*
***************** See Rev Note #43 ********************
*
T1 CMP #$f ;if any page<f (<block 8) requested
*******************************************************
 BCC TZIP ;it is invalid
*
TREG1 LDX #0 ;X contains number of iterations
 LDA BLOCK ;use true block number
 CMP #$5D ;beyond 8K blocks?
 BCC TR1 ;no, do normal
 SBC #$50 ;else subtract offset
GoTimes2 JMP Times2 ;and multiply by 2
* 
* Determine which 8K chunk it is in, place in X;
* block offset into chunk goes into Y.
*
TR1 SEC  
 SBC #$8 ;block = block -6
TR2 CMP #$11 ;if <=17, done
 BCC TR3 ;yup, got iteration
 SBC #$11 ;else block =block -17
 INX ;count iteration
 BPL TR2 ;branch always
 DFB $00 ;just in case
TR3 TAY ;remainder in Y
*
* If remainder is 1 it's an index block: start index
* blocks at $1000,$2000..$19FF) 
*    If remainder is 0, it is first data block in 8K
* chunk.  Page is 32 + (16 * X). 
*    Otherwise, it is some other data block. 
* Page is 32 + (16 * X) + (2 * Y) 
*
 CPY #1 ;is it index block?
 BNE TR4 ;no
 TXA ;index = 2*(8+X)
 CLC 
 ADC #8 
 BNE Times2 ;multiply by 2
TR4 INX ;need iteration+1
 TXA ;page = 2 * (16 + 8X)      
 ASL A
 ASL A 
 ASL A
 ASL A
 STA R1
 TYA ;get offset into 8K chunk
 BEQ TR5 ;if 0, no offset
 DEY ;else offset = 2 * Y
 TYA
TR5 CLC 
 ADC R1
Times2 ASL A ;acc=2*acc
 JSR BLOCKDO1 ;store in R1 and xfer
 JMP ExitCard ;and return
*
* When Block 3 is requested, the bitmap is returned.  The
* Real bitmap is only 16 bytes long (BITMAP); the rest of
* the block is synthesized.  The temporary buffer at $800
* is used to build/read a full size bitmap block.
*
TBMAP LDA #<ABUF1 ;use temporary buffer as BLOCK
 STA R1
 JSR SETPTR ;Set pointers/test read-write 
 BCS BITWRT ;its a write!
*
BITRD JSR CLRBUF2 
*
 LDY #$F ;now put real bitmap there
BITRD2 LDA BITMAP,Y
 STA (A1L),Y
 DEY
 BPL BITRD2
 JSR BLOCKDO ;move temp buf to user buf
 JMP ExitCard
*
BITWRT JSR BLOCKDO ;move user buf to temp buf
 JSR SETPTR ;Set pointers
 LDY #$F ;move temp buf to bitmap
BITWRT1 LDA (A4L),Y ;(pointer set by SETPTR) 
 STA BITMAP,Y
 DEY
 BPL BITWRT1
 JMP ExitCard
*
FormatFlag DFB 0 ;not formatted yet
*
TCMD DS 1,0 ;command byte
TUNIT DS 1,0 ;unit byte (not used)
R2L DS 1,0 ;low byte of user buffer
R2 DS 1,0 ;hi byte of user buffer
R1 DS 1,0 ;page requested
*
BITMAP DFB $00,$FF,$FF,$FF ;blocks 0-7 used 
 DFB $FF,$FF,$FF,$FF
 DFB $FF,$FF,$FF,$FF
 DFB $FF,$FF,$FF,$FE
*
Vdir EQU * ;start of vdir
Type_NameL DFB $F3 ;storage type F, namelength 3
 MSB OFF
VName ASC "RAM"
*
Access DFB $C3 ;Destroy, Rename, Read enabled
Entry_Len DFB $27 ;entry length
Entries_Per_Block DFB $0D 
File_Count DFB 0,0
Map_Pointer DFB 3,0 ;Block 3 
Total_Blocks DFB $7f        ;128 blocks 
*
ExitCard LDA EnblRAM1 ;restore lang card
 LDA EnblRAM1 
 PLA ;get 80STORE
 BPL Ex0 ;80STORE wasn't on
 STA Store80On
Ex0 JMP $3EF ;Jump around PassIt (3ED,3EE)
 DS $3EF-*,0 ;pad thru $3EE 
 LDA #>NoErr ;set up return to NoErr
 STA PassIt
 LDA #<NoErr
Ex1 STA PassIt+1 ;also used by BlockWrite 
 CLC ;transfer card to main
 CLV ;use standard zp/stk
 JMP XFER ;there's no place like home...
*  NOTE: The previous section of code MUST NOT use $3FE & $3FF
*        since the Interrupt Vector must go there if AUX interrupts
*        are to be used.
 PAGE
*
* Transfer card part of the driver to the card
* Transfer front part of the driver to lang.card
*
RAMDest EQU $0200
RAMDest1 EQU RAMDest+$100
LCDest EQU $FF00 
*
 ifeq os-ProDOS
*
**************** See Rev Note #60 *****************
*
Srce equ $2b00 ; Note: THIS MUST CHANGE WHEN THINGS GROW!
***************************************************
 fin
 ifeq os-EdNet
Srce equ $2b00 ; The loader is bigger in EdNet's Version.
 fin
RAMSrc EQU Srce+$100
RAMSrc1 EQU Srce+$200  
LCSrc EQU Srce+$300
*
DEVNUM EQU $B0 ;Slot 3, Drive 2 ($30 + hi bit set)
DEVADR EQU $BF10 ;Base of Device addresses 
DEVCNT EQU $BF31
DEVLST EQU $BF32
*
 ORG Srce
*
* Move LCSrc to LCDest
*
 LDY #$99 ;move $9A bytes 
MvLC LDA LCSrc,Y ;get a byte of source
 STA LCDest,Y
 DEY
 CPY #$FF
 BNE MVLC
*
* Move RAMSrc to RAMDest
*
 LDX #>RAMSrc
 STX A1L ;source low
 DEX ;source end low
 STX A2L
 LDX #<RAMSrc ;source high
 STX A1H
 INX
 STX A2H ;end high
 LDA #>RAMDest
 STA A4L
 LDA #<RAMDest
 STA A4H
 SEC ;RAM to Card
 JSR MOVE
*
* Now install it into the system
*
 LDA #>LCDest ;put LC address into
 STA DEVNUM/8+DEVADR ;slot 3, drive 2 
 LDA #<LCDEST
 STA DEVNUM/8+DEVADR+1
 INC DEVCNT
 LDX DEVCNT
 LDA #DEVNUM+$F ;unit num of /RAM
 STA DEVLST,X
 RTS
 PAGE
*
 ORG LCDest 
EnterRAM EQU * ;/RAM entry point
 CLD 
*
 LDX #$B ;save 13 bytes of params
SAVPARMS LDA A1L,X  
 STA A1L1,X
 DEX
 BPL SAVPARMS
*
 LDX #1 ;save XFER Vectors too 
SVP1 LDA PassIt,X
 STA SP1,X
 DEX
 BPL SVP1
*
 LDA CMD ;get command
 BEQ STAT ;0=STATUS
 CMP #4 ;check for command too high
 BCS IOERR ;if it is, IO ERR
 EOR #$3 ;0=FORMAT,2=READ,1=WRITE
 STA CMD ;CMD=>0=Format,2=Read,1=Write
 BEQ FORMAT ;format the volume
 LDY BLOCK+1 ;check for enormous blocknum
 BNE IOERR ;io error if too big
 LDA BLOCK ;get the block number
 BMI IOERR ;largest block is $7F
*
* At this point, control is passed to the code in the
* alternate 64K.  It is used for read, write, and 
* format.  After the request is completed, control
* is always passed back to NoErr.
*
Format EQU *
*
 LDA #>EnterCard ;card entry point
 STA PassIt ;figure it out on card
 LDA #<EnterCard
GoCard STA PassIt+1 ;also used by MainWrt 
 SEC ;RAM->Card
 CLV ;start with original z.p.
 JMP XFER ;transfer control
*
*
IOERR LDA #XDIOERR ;get err num
 BNE ERROUT ;and return
WPERR LDA #XDWPERR ;write protect err
ERROUT SEC ;flag error
 BCS Restore ;restore cmd and unitnum
*
STAT EQU *
NoErr LDA #0 ;no error
 CLC ;flag no error
Restore PHP ;save status
 PHA ;save error code
*
 LDX #$B ;restore 13 bytes of params
RSTPRMS LDA A1L1,X 
 STA A1L,X  
 DEX
 BPL RSTPRMS
*
 LDA SP1 ;restore XFER params
 BIT $6060 ;This instruction is to put an RTS at $FF58 as in ROM
 STA PassIt
 LDA SP1+1
 STA Passit+1
*
; -------------------- See rev note 21 -----------------------
 PLA ;get error
 PLP ;get status
; ------------------------------------------------------------
 RTS ;and return
*
MainWrt STA WrCardRAM ;xfer data to card
 LDY #0
MW1 LDA (A1L),Y ;pointers set in card by SETPTR
 STA (A4L),Y 
 LDA (A2L),Y
 STA (A3L),Y
 DEY
 BNE MW1
 STA WrMainRAM ;done writing Card
*
 LDA #>DoneWrt
 STA PassIt
 LDA #<DoneWrt
 JMP GoCard
*
SP1 DS 2,0 
A1L1 DS $C,0 ;13 bytes of storage
FrontLen EQU *-EnterRAM
*
***************** See Rev Note #EN1 ******************
*
 ifeq os-EdNet
 lda $c083 ; Switch in bank 2.
 jsr $d400 ; Go do RWTS.
 sta $c08b ; Switch bank 1 back in preserving status!
 rts  ; Back to caller.
wherearewe equ *
 fin
*****************************************************
